#ifndef __CLX_CLOUD_HPP__
#define __CLX_CLOUD_HPP__

#include "data.hpp"
#include <unistd.h>
#include "httplib.h"

#define SERVER_ADDR "101.43.252.201"
#define SERVER_PORT 8888

namespace clx_cloud {
    class Backup {
        private:
            std::string _back_dir;
            DataManager *_data;
        public:
            Backup(const std::string &back_dir, const std::string &back_file)
                : _back_dir(back_dir) {
                    _data = new DataManager(back_file);
            }

            // 创建文件唯一标识
            std::string GetFileIdentifier(const std::string &filename) {
                FileUtil fu(filename);
                std::stringstream ss;
                ss << fu.FileName() << "-" << fu.FileSize() << "-" << fu.LastMTime();
                return ss.str();
            }

            bool Runmodule() {
                while (1) {
                        // 1 遍历获取指定文件夹中所有文件
                        FileUtil fu(_back_dir);
                        std::vector<std::string> array;
                        fu.ScanDirectory(&array);
                        // 2 逐个判断文件是否需要上传
                        for (auto &a : array) {
                            if (IsNeedUpload(a)) {
                                // 如果需要上传则进行上传
                                std::cout << a << " need upload!" << std::endl;
                                if (Upload(a) == true) {
                                    std::cout << a << " upload success !" << std::endl;
                                    _data->Insert(a, GetFileIdentifier(a)); // 新增文件备份信息
                                }
                                else {
                                    std::cout << a << "upload failed !" << std::endl; 
                                }
                            }
                        }
                        sleep(1);
                }
            }

            bool Upload(const std::string &filename) {
                // 1 获取文件数据
                FileUtil  fu(filename);
                std::string body;
                fu.GetContent(&body);
                // 2 搭建http客户端上传文件数据
                httplib::Client client(SERVER_ADDR, SERVER_PORT);
                httplib::MultipartFormData item;
                item.name = "file";
                item.content = body;
                item.filename = fu.FileName();
                item.content_type = "application/octet-stream";
                httplib::MultipartFormDataItems items; 
                items.push_back(item);
                auto res = client.Post("/upload", items);
                if (!res || res->status != 200) {
                    return false;
                }
                return true;
            } 

            bool IsNeedUpload(const std::string &filename) {
                // 需要上传的文件的判断条件：文件是新增的，不是新增的但是被修改过
                // 文件是新增的： 看一下有没有历史备份信息
                // 不是新增的但是被修改过：有历史信息，但是历史的唯一标识和当前最新的唯一标识不一致
                std::string id;
                if (_data->GetOneByKey(filename, &id) != false) {
                    // 有历史信息
                    std::string  new_id = GetFileIdentifier(filename);
                    if (new_id == id) { // 上传后没有被修改过
                        return false;
                    }
                }
                // 一个文件比较大，正在慢慢拷贝到这个目录下，拷贝需要一个过程
                // 如果每次遍历都会判断标识符不一致，则一个10G大小的文件会上传上百次
                // 因此应该怕断一个文件一段时间都没有被修改过，才上传
                FileUtil fu(filename);
                if (time(NULL) - fu.LastMTime() > 3) { // 3秒之内没有被修改过--认为文件还在修改中
                    return false;
                }
                return true;
            }
    };
}
#endif